package
{
	import com.adobe.utils.AGALMiniAssembler;
	
	import flash.display.Bitmap;
	import flash.display.Sprite;
	import flash.display.Stage3D;
	import flash.display.StageAlign;
	import flash.display.StageScaleMode;
	import flash.display3D.Context3D;
	import flash.display3D.Context3DBlendFactor;
	import flash.display3D.Context3DCompareMode;
	import flash.display3D.Context3DProgramType;
	import flash.display3D.Context3DRenderMode;
	import flash.display3D.Context3DTextureFormat;
	import flash.display3D.Context3DTriangleFace;
	import flash.display3D.Context3DVertexBufferFormat;
	import flash.display3D.IndexBuffer3D;
	import flash.display3D.Program3D;
	import flash.display3D.VertexBuffer3D;
	import flash.display3D.textures.Texture;
	import flash.events.Event;
	import flash.geom.Matrix;
	import flash.geom.Matrix3D;
	import flash.geom.Rectangle;
	import flash.utils.getTimer;
	
	public class TestM2d extends Sprite
	{
		private static function makeOrthoProjection(w:Number, h:Number, n:Number, f:Number):Matrix3D
		{
			return new Matrix3D(Vector.<Number>
				([
					2/w, 0  ,       0,        0,
					0  , 2/h,       0,        0,
					0  , 0  , 1/(f-n), -n/(f-n),
					0  , 0  ,       0,        1
				]));
		}
		
		private static var W:int = 640;
		private static var H:int = 480;
		
		[Embed( source = "res/molepeople.jpg" )]//CJ301-sky.jpg  molepeople.jpg
		private static var MolePeople:Class;
		
		[Embed( source = "res/role.png" )]//CJ301-sky.jpg  molepeople.jpg
		private static var M1:Class;
		
		
		private var _context3D:Context3D;
		private var _shaderProgram:Program3D;
		private var _indexBuffer:IndexBuffer3D;
		private var _sprite:MoleSprite;
		private var _sprite2:MoleSprite;
		private var _texture:Texture;
		private var _texture2:Texture;
		private var _buffer:VertexBuffer3D;
		private var viewMatrix:Matrix3D;
		
		public function TestM2d():void 
		{
			this.addEventListener(Event.ENTER_FRAME,frame);
		}
		private function initViewMatrix():void{
			viewMatrix = new Matrix3D();
			viewMatrix.appendTranslation(-W/2, -H/2, 0);
			viewMatrix.appendScale(1, -1, 1);
			viewMatrix.append(makeOrthoProjection(W, H, 0, 100));
		}
		private function frame(evnet:Event):void{
			this.removeEventListener(Event.ENTER_FRAME,frame);
			stage.scaleMode = StageScaleMode.NO_SCALE;
			stage.align = StageAlign.TOP_LEFT;
			W = stage.stageWidth;
			H = stage.stageHeight;
			var stage3D:Stage3D = stage.stage3Ds[0];
			stage3D.addEventListener(Event.CONTEXT3D_CREATE, initialize);
			stage3D.requestContext3D(Context3DRenderMode.AUTO);
		}
		private var modelSpriteList:Vector.<MoleSprite> = new Vector.<MoleSprite>;
		private function initialize(e:Event):void 
		{
			var stage3D:Stage3D = e.target as Stage3D;
			
			_context3D = stage3D.context3D;
			if (_context3D == null)
			{
				trace("oh no, context is null!");
				return;
			}
			
			trace(_context3D.driverInfo);
			try
			{
				_context3D.configureBackBuffer(W, H, 2, false);		
			}
			catch (e:Error)
			{
				trace(e);
			}

			
			_context3D.enableErrorChecking = true;
			
			//_context3D.setCulling(Context3DTriangleFace.NONE);
			//_context3D.setDepthTest(true, Context3DCompareMode.LESS_EQUAL);	
			//compile vertex shader
			var vertexShader:Array =
				[
					"dp4 op.x, va0, vc0", //4x4 matrix transform from 0 to output clipspace
					"dp4 op.y, va0, vc1",
					"dp4 op.z, va0, vc2",
					"dp4 op.w, va0, vc3",
					"mov v0, va1.xyzw"    //copy texcoord from 1 to fragment program
				];
			var vertexAssembler:AGALMiniAssembler = new AGALMiniAssembler();
			vertexAssembler.assemble(flash.display3D.Context3DProgramType.VERTEX, vertexShader.join("\n"));
			
			//compile fragment shader
			var fragmentShader:Array =
				[
					"mov ft0, v0			\n" ,
					"tex ft1, ft0, fs1 <2d>	\n" ,	// sample texture 0
					"mov oc, ft1\n"
				];
			/*var fragmentShader:Array =
				[
					"mov ft0, v0\n",
					"tex ft1, ft0, fs1 <2d,clamp,linear>\n", //sample texture 1		
					"mov oc, ft1\n"
				];*/
			var fragmentAssembler:AGALMiniAssembler = new AGALMiniAssembler();
			fragmentAssembler.assemble(flash.display3D.Context3DProgramType.FRAGMENT, fragmentShader.join("\n"));
			
			_shaderProgram = _context3D.createProgram();
			_shaderProgram.upload(vertexAssembler.agalcode, fragmentAssembler.agalcode);
			
			_indexBuffer = _context3D.createIndexBuffer(6);
			_indexBuffer.uploadFromVector(Vector.<uint>([0, 1, 2, 0, 2, 3 ]), 0, 6);
			
			_buffer     = _context3D.createVertexBuffer(4, 4);
			_buffer.uploadFromVector(Vector.<Number>
				([
					-1.0, 1.0, 0.0, 1.0,
					-1.0,-1.0, 0.0, 0.0,
					1.0,-1.0, 1.0, 0.0,
					1.0, 1.0, 1.0, 1.0
				]), 0, 4);
			
			_context3D.setVertexBufferAt(0, _buffer, 0, Context3DVertexBufferFormat.FLOAT_2); //xy
			_context3D.setVertexBufferAt(1, _buffer, 2, Context3DVertexBufferFormat.FLOAT_2); //uv
			
			var bitmap:Bitmap = new MolePeople();
			_texture = _context3D.createTexture(256, 256, Context3DTextureFormat.BGRA, false);
			_texture.uploadFromBitmapData(bitmap.bitmapData);
			
			
			bitmap = new M1();
			_texture2 = _context3D.createTexture(256, 256, Context3DTextureFormat.BGRA, false);
			_texture2.uploadFromBitmapData(bitmap.bitmapData);
			
			_sprite = new MoleSprite(_context3D);
			_sprite2 = new MoleSprite(_context3D);
			
			_context3D.setBlendFactors(Context3DBlendFactor.ONE, Context3DBlendFactor.ONE_MINUS_SOURCE_ALPHA);
			
			_context3D.setProgram(_shaderProgram);
			
			initViewMatrix();
			
			initList();
			
			addEventListener(Event.ENTER_FRAME, renderFrame)
		}
		
		private function initList():void{
			for(var i:int;i<200;i++){
				var sp:MoleSprite = new MoleSprite(_context3D);
				sp.width = sp.height = 100 + 10*Math.random();
				sp.viewMatrix = this.viewMatrix;
				if(i%2){
					sp._texture = _texture
				}else{
					sp._texture = _texture2;
				}
				sp._indexBuffer = _indexBuffer;
				modelSpriteList.push(sp);
			}
		}
		
		private function renderFrame(e:Event):void
		{
			var timeSec:Number = getTimer() / 500;
			
			_context3D.clear(0, 1, 0, 0);
			
			//transform sprite
			/*_sprite.width    = 256;
			_sprite.height   = 256;
			_sprite.x        += 2;
			_sprite.y        += 2;
			
			_sprite2.width    = 256;
			_sprite2.height   = 256;
			_sprite2.x        += 1;
			_sprite2.y        += 1;
			
			_context3D.clear(0, 1, 0, 0);
			
			var mvp:Matrix3D;
			
			mvp = 	_sprite.getWorldTransform()
			mvp.append(viewMatrix);
			_context3D.setProgramConstantsFromMatrix(Context3DProgramType.VERTEX, 0, mvp, true);
			_context3D.setTextureAt(1, _texture);
			_context3D.drawTriangles(_indexBuffer, 0, 2);
			
			mvp = _sprite2.getWorldTransform()
			mvp.append(viewMatrix);
			_context3D.setProgramConstantsFromMatrix(Context3DProgramType.VERTEX, 0, mvp, true);
			_context3D.setTextureAt(1, _texture2);
			_context3D.drawTriangles(_indexBuffer, 0, 2);*/
			
			
			for(var i:int;i<modelSpriteList.length;i++){
				var sp:MoleSprite = modelSpriteList[i];
				sp.processLogic();
				sp.render();
			}
			
			
			_context3D.present();
		}
		
		
		
	}
}